package org.bes.WinClass;

import org.bes.api.IBackup;
import org.bes.utils.StrPathUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.json.*;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.nio.file.StandardOpenOption;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import static org.bes.WinClass.FileManager.*;
import static org.bes.WinClass.VersionControl.fileVersions;

public class Backup extends PatchInfo implements IBackup {

    private static final Logger log = LoggerFactory.getLogger(Backup.class);
    private static final String originVerDirName = "apache-patch-V1.0.0";

    public Backup() {
        super();
    }

    public void backup() throws IOException {
        // Ensure the backup folder exists
        Files.createDirectories(FileManager.getTmpDir());

        for (Map.Entry<String, File> entry : fileListQueue) {

            String symbol = entry.getKey();
            File file = entry.getValue();

            Path fileRelativePath = StrPathUtils.stripFirstPart(FileManager.getBackupDir().relativize(file.toPath()));
            Path backupPath = FileManager.getTmpDir().resolve(fileRelativePath);

            // 获取文件的版本号
            String version = fileVersions.getOrDefault(fileRelativePath.toString(), "UNKNOWN");

            // 处理 + 号文件
            if ("+".equals(symbol)) {

                Files.createDirectories(backupPath.getParent());
                try {
                    // Copy the file to backup directory
                    backupOriginVersion(fileRelativePath);
                    Files.copy(FileManager.getSourceDir().resolve(fileRelativePath), backupPath, StandardCopyOption.REPLACE_EXISTING);
                } catch (IOException e) {
                    log.error("Failed to backup file: " + e.getMessage());
                }

                // Log backup status with patch version info (if any)
                log.info(file.getName() + " file has been backed up to the tmp folder in the current directory");

            }

            // 处理 - 号文件，直接备份到 tmp 文件夹
            if ("-".equals(symbol)) {

                // 判断文件路径是否是 JSON 文件
                if (file.toString().endsWith(".json")) {
                    try {
                        jsonRead(file);  // 读取 JSON 文件并处理备份
                    } catch (FileNotFoundException e) {
                        log.error("Error reading JSON file: {}", e.getMessage());
                    }
                } else {
                    log.error("backup delete file not json");
                }

            }


        }
    }

    public void backupOriginVersion(Path relativePath) throws IOException {


        // 获取文件的版本号
        String version = fileVersions.getOrDefault(relativePath.toString(), "UNKNOWN");

        if ("1.0.0".equals(version)) {
            Path versionBackupDir = FileManager.getBackupDir().resolve(originVerDirName);
            Files.createDirectories(versionBackupDir); // 确保目录存在

            Path versionBackupPath = versionBackupDir.resolve(relativePath);
            Files.createDirectories(versionBackupPath.getParent());
            Files.copy(getSourceDir().resolve(relativePath), versionBackupPath, StandardCopyOption.REPLACE_EXISTING);

            log.info("Backed up {} to {}", relativePath.getFileName(), versionBackupPath);

        }
    }

    // 处理 JSON 文件中的备份逻辑
    public void jsonRead(File file) throws FileNotFoundException {
        // Log the JSON file path
        log.info("Found JSON file: {}", file.getAbsolutePath());

        try (JsonReader jsonReader = Json.createReader(new FileReader(file))) {
            JsonObject rootObject = jsonReader.readObject();
            JsonArray deleteFilesArray = rootObject.getJsonArray("delete_files");

            // Step 1: Process the delete_files array
            for (JsonValue fileValue : deleteFilesArray) {



                // Check if the file entry is a regular file path or a JAR object
                if (fileValue.getValueType() == JsonValue.ValueType.STRING) {
                    // Regular file, process as before
                    String relativePath = fileValue.toString().replace("\"", "");
                    Path backupPath = FileManager.getTmpDir().resolve(relativePath);
                    Path absolutePath = FileManager.getSourceDir().resolve(relativePath);  // Resolve to absolute path
                    Files.createDirectories(backupPath.getParent());
                    try {
                        // Copy the file to backup directory
                        backupOriginVersion(Path.of(relativePath));
                        Files.copy(absolutePath, backupPath, StandardCopyOption.REPLACE_EXISTING);
                    } catch (IOException e) {
                        log.error("Failed to backup file: " + e.getMessage());
                    }

                } else if (fileValue.getValueType() == JsonValue.ValueType.OBJECT) {
                    // It's a JSON object containing a JAR file and classes to delete
                    JsonObject jarObject = (JsonObject) fileValue;
                    String jarFilePath = jarObject.getString("jar_file");

                    // Step 2: Process the JAR file (just add the JAR file for backup)
                    Path jarAbsolutePath = FileManager.getSourceDir().resolve(jarFilePath);  // Resolve JAR path
                    File jarFile = jarAbsolutePath.toFile();

                    String relativePath = jarFilePath.replace("\"", "");
                    Path backupPath = FileManager.getTmpDir().resolve(relativePath);
                    backupOriginVersion(Path.of(relativePath));
                    Files.copy(jarAbsolutePath, backupPath, StandardCopyOption.REPLACE_EXISTING);

                    // Add to fileListMap for JAR files
                    //fileListQueue.add(new AbstractMap.SimpleEntry<>("-", jarFile));
                    log.info("JAR file {} will be backed up. Classes to delete are ignored.", jarFilePath);
                }
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }



}
